#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <unistd.h>
#include <string.h>

#include <libgen.h>

#define SERVER_IP "10.35.161.14"
#define SERVER_PORT 69

// ./upload 明日之子.jpg
int main(int argc, char const *argv[])
{   
    if(argc != 2) return -1;
    int sock=socket(AF_INET, SOCK_DGRAM, 0);

    int fd = open(argv[1], O_RDONLY);
    if(fd < 2) {
        perror("open");
        close(sock);
        return -1;
    }

    // 定义上传文件的TFTP协义报文
    char buf[128] = "";
    // 如果argv[1] 是文件路径，只获取文件名: char * basename(char *path) 
    sprintf(buf, "%c%c%s%c%s%c", 0, 2, basename((char *)argv[1]), 0, "octet", 0);

    // 定义TFTP服务器的地址信息
    struct sockaddr_in server = {
        .sin_family = AF_INET,
        .sin_port = htons(SERVER_PORT),
        .sin_addr.s_addr = inet_addr(SERVER_IP)
    };

    // 发送上传报文的请求
    sendto(sock, buf, 9+strlen(argv[1]), 0, (struct sockaddr *)&server, sizeof(server));

    char databuf[516] = "";
    // 循环接收服务器发送的ACK
    uint16_t write_bnum = 1;  // 向服务发送数据的块号
    while(1){
        bzero(databuf, 516);

        struct sockaddr_in data_addr;
        socklen_t data_addr_len = sizeof(data_addr);

        ssize_t datalen = recvfrom(sock, databuf, 128, 0,(struct sockaddr *)&data_addr, &data_addr_len);
        // 验证请求码是4还是5
        if(databuf[1] == 4){  // 服务器可以接收数据
            uint16_t bnum = ntohs( *((uint16_t *)(databuf+2)) ); // 第一次 0            
            // 将fd 文件中的数据读取512字节到 databuf+4的位置
            ssize_t read_len = read(fd, databuf+4, 512);

            // 修改操作码
            databuf[1] = 3; // 数据包

            // 修改数据块号
            *((uint16_t *)(databuf+2)) = htons(write_bnum++);

            // 向TFTP服务器发送数据
            sendto(sock, databuf, 4+read_len, 0, (struct sockaddr *)&data_addr, sizeof(data_addr));

            // 验证当前数据是否为最后一块
            if(read_len < 512) {
                break;
            }
            

        }else if(databuf[1] == 5){
            printf("error: %s\n", databuf+4);
            break;
        }
    }

    close(fd);
    close(sock);
    printf("--over--\n");
    
    return 0;
}
